package com.oj.judge.service.impl;

import com.oj.judge.JudgeManger;
import com.oj.judge.codesandbox.CodeSandBox;
import com.oj.judge.codesandbox.CodeSandBoxFactory;
import com.oj.judge.codesandbox.impl.CodeSandBoxProxy;
import com.oj.judge.domain.*;
import com.oj.judge.enums.JudgeResultMessageEnum;
import com.oj.judge.mapper.SubmissionMapper;
import com.oj.judge.service.JudgeService;
import com.oj.judge.strategy.JudgeStrategy;
import com.oj.judge.strategy.impl.DefaultJudgeStrategyImpl;
import com.oj.problem.domain.Problem;
import com.oj.problem.domain.TestCase;
import com.oj.problem.service.IProblemService;
import com.oj.problem.service.ITestCaseService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Classname JudgeServiceImpl
 * @Description 判题服务实现类
 * @Date 2025/3/16 19:17
 * @Created by xxx
 */
@Service
@Slf4j
public class JudgeServiceImpl implements JudgeService {

    private static final int MAX_RETRIES = 3;  // 减少最大轮询次数，避免不必要的等待
    private static final int RETRY_DELAY = 500; // 减少每次轮询间隔，提高效率
    @Autowired
    private ITestCaseService testCaseService; // 获取测试用例
    @Autowired
    private IProblemService problemService; // 获取题目信息
    @Value("${codesandbox.type}")
    private String value; // 获取代码沙箱类型
    @Autowired
    private SubmissionMapper submissionMapper; // 数据库操作

    @Override
    public void judge(Submission submission) {
        try {
            log.info("开始判题：提交ID={}", submission.getId());
            Long problemId = submission.getProblemId();
            Problem problem = problemService.selectProblemById(problemId);
            if (problem == null) {
                throw new IllegalArgumentException("题目信息不存在，problemId=" + problemId);
            }
            List<TestCase> testCases = problem.getTestCaseList();
            CodeSandBox codeSandbox = new CodeSandBoxProxy(CodeSandBoxFactory.NewInstance(value));
            String code = submission.getCode();
            String language = submission.getLanguage();
            List<String> inputList = testCases.stream().map(TestCase::getInput).collect(Collectors.toList());
            ExecuteCodeRequest executeRequest = ExecuteCodeRequest.builder()
                    .code(code)
                    .language(language)
                    .inputList(inputList)
                    .build();
            ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeRequest);
            List<String> outputList = executeCodeResponse.getOutputList();
            Integer time = executeCodeResponse.getJudgeResult().getTime();
            Integer memory = executeCodeResponse.getJudgeResult().getMemory();
            JudgeContext judgeContext = new JudgeContext();
            judgeContext.setJudgeResult(executeCodeResponse.getJudgeResult());
            judgeContext.setSubmission(submission);
            judgeContext.setInputList(inputList);
            judgeContext.setOutputList(outputList);
            judgeContext.setProblem(problem);
            judgeContext.setTestCases(testCases);
            JudgeStrategy judgeStrategy = new DefaultJudgeStrategyImpl();
            JudgeResult judgeInfo = new JudgeManger().doJudge(judgeContext);
            updateSubmissionInfo(submission, judgeInfo.getStatus(), time, memory, judgeInfo.getMessage());
        } catch (Exception e) {
            log.error("判题失败：提交ID={}", submission.getId(), e);
            updateSubmissionInfo(submission, JudgeResultMessageEnum.SystemError.getValue(), 0, 0, "判题失败：" + e.getMessage());
        }
    }

    private void updateSubmissionInfo(Submission submission, String status, Integer time, Integer memory, String message) {
        submission.setUpdateTime(LocalDateTime.now());
        submission.setStatus(status);
        submission.setTime(time);
        submission.setMemory(memory);
        submission.setMessage(message);
        submissionMapper.updateById(submission);
    }
}
